#pragma once

#include "channel.h"

namespace ns_conn
{
    using namespace ns_channel;

    // 连接中的信道管理
    class Connection
    {
    public:
        using ptr = shared_ptr<Connection>;

        Connection(shared_ptr<ConsumerManage> &cmp,
                   const muduo::net::TcpConnectionPtr &conn,
                   const ProtobufCodecPtr &codec,
                   const shared_ptr<VirtualHost> &host,
                   const shared_ptr<ThreadPool> &pool)
            : _cmp(cmp), _conn(conn), _codec(codec), _host(host), _pool(pool)
        {
            _channels = make_shared<ChannelManage>();
        }

        void createChannel(const openChannelRequestPtr &req)
        {
            _channels->createChannel(req->cid(), _cmp, _conn, _codec, _host, _pool);
            buildResponseSend(req->rid(), req->cid(), true);
        }

        void closeChannel(const closeChannelRequestPtr &req)
        {
            _channels->closeChannel(req->cid());

            buildResponseSend(req->rid(), req->cid(), true);
        }

        Channel::ptr getChannel(const string &cid)
        {
            return _channels->getChannel(cid);
        }

        ~Connection() {}

    private:
        void buildResponseSend(const string &rid, const string &cid, const bool &ok)
        {
            // 构建响应
            basicCommonResponse rsp;
            rsp.set_rid(rid);
            rsp.set_cid(cid);
            rsp.set_ok(ok); // 取决于请求执行成功与否
            _codec->send(_conn, rsp);
        }

    private:
        ChannelManage::Ptr _channels; // 对信道进行管理
        // 信道管理所需对象
        shared_ptr<ConsumerManage> _cmp;    // 消费者管理
        muduo::net::TcpConnectionPtr _conn; // 通信连接(数据发送)
        ProtobufCodecPtr _codec;            // 协议处理器(没必要重复定义，共用)
        shared_ptr<VirtualHost> _host;      // 虚拟机管理句柄
        shared_ptr<ThreadPool> _pool;       // 线程池(用于数据传输给消费者)
    };

    // 连接的管理
    class ConnectionManage
    {
    public:
        void createConnection(shared_ptr<ConsumerManage> &cmp,
                              const muduo::net::TcpConnectionPtr &conn,
                              const ProtobufCodecPtr &codec,
                              const shared_ptr<VirtualHost> &host,
                              const shared_ptr<ThreadPool> &pool)
        {
            unique_lock<mutex> lck(_mtx);

            if (_connections.count(conn))
            {
                LOG(WARNING) << "创建连接失败,该连接已经存在" << endl;
                return;
            }
            Connection::ptr self = make_shared<Connection>(cmp, conn, codec, host, pool);
            _connections.insert(make_pair(conn, self));
        }

        void closeConnection(const muduo::net::TcpConnectionPtr &conn)
        {
            unique_lock<mutex> lck(_mtx);

            if (!_connections.count(conn))
            {
                LOG(WARNING) << "关闭连接失败,该连接不存在" << endl;
                return;
            }
            _connections.erase(conn);
        }

        Connection::ptr getConnection(const muduo::net::TcpConnectionPtr &conn)
        {
            unique_lock<mutex> lck(_mtx);

            if (!_connections.count(conn))
            {
                LOG(WARNING) << "获取连接失败,该连接不存在" << endl;
                return Connection::ptr();
            }
            return _connections[conn];
        }

    private:
        mutex _mtx;
        unordered_map<muduo::net::TcpConnectionPtr, Connection::ptr> _connections;
    };
}